package com.fowo.api.common.util;

import com.fowo.api.common.annotaion.Sensitive;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;

import java.util.*;
import java.util.function.Function;

/**
 * 提供数据相关处理方法
 * @author yl_ls
 */
@SuppressWarnings("unused")
@UtilityClass
@Slf4j
public class DataUtils {

    /**
     * 数据去敏感
     * @param object 如果是 List 也会处理每个项
     */
    public void desensitization(Object object) {
        if (object == null) {
            return;
        }
        final Class<?> objectClass = object.getClass();
        if(List.class.isAssignableFrom(objectClass)) {
            for(Object item: (List)object) {
                desensitization(item);
            }
            return;
        }
        ReflectionUtils.doWithFields(objectClass, field -> {
            Sensitive sensitive = field.getAnnotation(Sensitive.class);
            if (sensitive != null) {
                field.setAccessible(true);
                Object value = field.get(object);
                if (value == null) {
                    return;
                }
                if (sensitive.value() == Sensitive.SensitiveType.Null) {
                    // 直接清空
                    field.set(object, null);
                    return;
                }
                if(!CharSequence.class.isAssignableFrom(field.getType())) {
                    log.warn("Sensitive 使用星号替换时只能用于字符串类型字段");
                    return;
                }
                String strValue = value.toString();
                int startStarIndex = 0;
                int endStarIndex = strValue.length();
                if(strValue.length() > 1) {
                    if(sensitive.value() == Sensitive.SensitiveType.StartStar) {
                        endStarIndex = strValue.length() / 2;
                    }
                    else if(sensitive.value() == Sensitive.SensitiveType.CenterStar) {
                        startStarIndex = strValue.length() / 3;
                        endStarIndex = Math.max(startStarIndex + 1, endStarIndex - startStarIndex);
                    }
                    else if(sensitive.value() == Sensitive.SensitiveType.EndStar) {
                        startStarIndex = Math.max(0, endStarIndex - startStarIndex);
                    }
                }
                strValue = strValue.substring(0, startStarIndex) + "*".repeat(endStarIndex - startStarIndex) + strValue.substring(endStarIndex);
                field.set(object, strValue);
            }
        });
    }

    /**
     * 将列表类数据转换为对应 Map
     * @param collection 列表数据
     * @param keySelector 列表项键选择器
     * @param <K> 键类型
     * @param <V> 值类型
     */
    public <K,V> Map<K, V> listToMap(Collection<V> collection, Function<V, K> keySelector) {
        Map<K,V> map = new HashMap<>(collection.size());
        for (V v : collection) {
            map.put(keySelector.apply(v), v);
        }
        return map;
    }

    /**
     * 将列表类数据转换为对应 Map
     * @param collection 列表数据
     * @param keySelector 列表项键选择器
     * @param valueSelector 列表项值选择器
     * @param <K> 键类型
     * @param <I> 列表项类型
     * @param <V> 值类型
     */
    public <K,I,V> Map<K, V> listToMap(Collection<I> collection, Function<I, K> keySelector, Function<I, V> valueSelector) {
        Map<K,V> map = new HashMap<>(collection.size());
        for (I v : collection) {
            map.put(keySelector.apply(v), valueSelector.apply(v));
        }
        return map;
    }
}
